﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Linq;

namespace Nethereum.RPC.ClassesExtractor
{
    public class RequestUnityGenerator
    {
        public string GenerateToFile(string path, List<RequestInfo> requestInfoCollection)
        {
            using (var fileOutput = System.IO.File.CreateText(path))
            {
                fileOutput.Write(GenerateDocument(requestInfoCollection));
                fileOutput.Flush();
            }
            return path;
        }

        public string GenerateDocument(List<RequestInfo> requestInfoCollection)
        {
            return
$@"
/*
Autogenerated file from Nethereum.RPC
*/
using System;
using System.Text;
using Nethereum.JsonRpc.Client;
using Newtonsoft.Json;
using System.Collections;
using Nethereum.Hex.HexTypes;
using Nethereum.RPC.Eth.DTOs;
using System.Collections.Generic;

namespace Nethereum.Unity.Rpc
{{

{Generate(requestInfoCollection)}

}}
";
        }

        public string Generate(List<RequestInfo> requestInfoCollection)
        {
            var stringBuilder = new StringBuilder();
            foreach (var requestInfo in requestInfoCollection)
            {
                stringBuilder.AppendLine(Generate(requestInfo));
            }
            return stringBuilder.ToString();
        }

        public string Generate(RequestInfo requestInfo)
        {
            var className = requestInfo.RequestType.Name;
            var classTypeName = requestInfo.RequestType.FullName;
            if (classTypeName.StartsWith("Nethereum."))
            {
                classTypeName = classTypeName.Substring("Nethereum.".Length);
            }
            var returnType = requestInfo.ReturnType.FullName;
            var parameters = requestInfo.BuildRequestParameters.FirstOrDefault(z => z.FirstOrDefault(t => t.IsOptional == true && t.Name == "id") != null);
            var paramMethod = string.Join(", ", parameters.OrderBy(y => y.Position).Where(x => x.Name != "id").Select(
                  n => { return n.ParameterType.FullName + " " + n.Name + (n.IsOptional ? " = null" : ""); }));

            var paramCall = string.Join(", ", parameters.Where(x => x.Name != "id").OrderBy(y => y.Position).Select(n => n.Name));

            //forcing null the default value

            return $@"
    public class {className}UnityRequest : UnityRpcRequest<{returnType}>
    {{
        private readonly {classTypeName} _{FirstLetterToLower(className)};

        public {className}UnityRequest(string url, JsonSerializerSettings jsonSerializerSettings = null, Dictionary<string, string> requestHeaders = null):base(url, jsonSerializerSettings, requestHeaders)
        {{
            _{FirstLetterToLower(className)} = new {classTypeName}(null);
        }}

        public {className}UnityRequest(IUnityRpcRequestClientFactory unityRpcClientFactory):base(unityRpcClientFactory)
        {{
            _{FirstLetterToLower(className)} = new {classTypeName}(null);
        }}

        public IEnumerator SendRequest({paramMethod})
        {{
            var request = _{FirstLetterToLower(className)}.BuildRequest({paramCall});
            yield return SendRequest(request);
        }}
    }}
                ";

        }

        public string FirstLetterToLower(string name)
        {
            return name.Substring(0, 1).ToLower() + name.Substring(1);
        }

    }
}

